home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / xcharts0.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  28KB  |  983 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: xcharts0.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: xcharts0.c,v 1.3 1995/07/02 22:22:23 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41.  
  42. #ifdef GRAPH
  43. /*
  44. ******************************************************************************
  45. ** Subchart Graphics Routines.
  46. ******************************************************************************
  47. */
  48.  
  49. /* Given a string, draw it on the screen using the given color. The       */
  50. /* position of the text is based the saved positions of where we drew the */
  51. /* text the last time the routine was called, being either directly below */
  52. /* in the same column or in the same row just to the right. This is used  */
  53. /* by the sidebar drawing routine to print a list of text on the chart.   */
  54.  
  55. /* Examples:
  56.  
  57.      DrawPrint(NULL, x,y);       Initialize the cursor to position (x,y)
  58.  
  59.      DrawPrint("bla",
  60.  
  61. */
  62.  
  63.  
  64.  
  65. int DrawPrint(sz, m, n)
  66. char *sz;
  67. int m, n;
  68. {
  69.   static int x0, x, y;
  70.  
  71.   if (sz == NULL)      /* Null string means just initialize position. */
  72.   {
  73.     x0 = x = m; y = n;
  74.     return y;
  75.   }
  76.  
  77.   if (y >= gs.yWin-1)  /* Don't draw if we've scrolled off the chart bottom. */
  78.     return y;
  79.  
  80.   DrawColor(m);
  81.   DrawSz(sz, x, y, dtLeft | dtBottom);
  82.  
  83.   /* If the second parameter is TRUE, we stay on the same line, otherwise */
  84.   /* when FALSE we go to the next line at the original column setting.    */
  85.  
  86.   if (n)
  87.     x += CchSz(sz)*xFont*gi.nScaleT;
  88.  
  89.   else
  90.   {
  91.     x = x0;
  92.     n = y;
  93.     y += yFont*gi.nScaleT;
  94.   }
  95.   return y;
  96. }
  97.  
  98.  
  99. /* Print text showing the chart information and house and planet positions */
  100. /* of a chart in a "sidebar" to the right of the chart in question. This   */
  101. /* is always done for the -v and -w graphic wheel charts unless the -v0    */
  102. /* switch flag is also set, in which case none of the stuff here is done.  */
  103.  
  104. void DrawInfo()
  105. {
  106.   char sz[cchSzDef];
  107.   ET et;
  108.   int i, y, a, s;
  109.  
  110. #ifdef INTERPRET
  111.   int tot, abo, lef;
  112.  
  113.   /* Hack: Just for fun, if interpretation is active (which normally has  */
  114.   /* no effect whatsoever on graphics) we'll decorate the chart a little. */
  115.  
  116.   if (us.fInterpret)
  117.   {
  118.     if (us.nScreenWidth & 1)
  119.     {
  120.       /* If screenwidth value is odd, draw a moire pattern in each corner. */
  121.  
  122.       abo = gs.yWin/(us.nScreenWidth/10);
  123.       lef = gs.xWin/(us.nScreenWidth/10);
  124.  
  125.       for (y = 0; y <= 1; y++)
  126.       {
  127.         for (i = 0; i <= 1; i++)
  128.         {
  129.           for (s = 0; s <= 1; s++)
  130.           {
  131.             for (a = 1; a < (s ? lef : abo)*2; a++)
  132.             {
  133.               DrawColor(a & 1 ? gi.kiGray : gi.kiOff);
  134.               DrawLine(i ? gs.xWin-1-lef : lef, y ? gs.yWin-1-abo : abo,
  135.                 s ? (i ? gs.xWin-1-a : a) : i*(gs.xWin-1),
  136.                 s ? y*(gs.yWin-1) : (y ? gs.yWin-1-a : a));
  137.             }
  138.           }
  139.         }
  140.       }
  141.     } 
  142.  
  143.     else
  144.     {
  145.       /* If screenwidth is even, draw spider web lines in each corner. */
  146.  
  147.       DrawColor(gi.kiGray);
  148.  
  149.       tot = us.nScreenWidth*3/20;
  150.       abo = gs.yWin/4;
  151.       lef = gs.xWin/4;
  152.  
  153.       for (y = 0; y <= 1; y++)
  154.       {
  155.         for (i = 0; i <= 1; i++)
  156.         {
  157.           for (a = 1; a < tot; a++)
  158.           {
  159.             DrawLine(i*(gs.xWin-1), y ? (gs.yWin-1-a*abo/tot) : a*abo/tot,
  160.               i ? gs.xWin-1-lef+a*lef/tot : lef-a*lef/tot, y*(gs.yWin-1));
  161.           }
  162.         }
  163.       }
  164.     }
  165.   }
  166. #endif
  167.  
  168.   if (!gs.fText || us.fVelocity)    /* Don't draw sidebar if */
  169.     return;                         /* -v0 flag is set.      */
  170.  
  171.   a = us.fAnsi;
  172.   us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS));
  173.   DrawColor(gi.kiLite);
  174.  
  175.   if (gs.fBorder)
  176.     DrawLine(gs.xWin-1, 0, gs.xWin-1, gs.yWin-1);
  177.  
  178.   gs.xWin += xSideT;
  179.   DrawPrint(NULL, gs.xWin-xSideT+xFontT-gi.nScaleT, yFont*7/5*gi.nScaleT);
  180.  
  181.   /* Print chart header and setting information. */
  182.  
  183.   sprintf(sz, "%s %s", szAppName, szVersionCore);
  184.   DrawPrint(sz, gi.kiOn, fFalse);
  185.  
  186.   if (*ciMain.nam)
  187.     DrawPrint(ciMain.nam, gi.kiLite, fFalse);
  188.  
  189.   if (Mon == -1)
  190.     sprintf(sz, "No time or space.");
  191.  
  192.   else if (us.nRel == rcComposite)
  193.     sprintf(sz, "Composite chart.");
  194.  
  195.   else
  196.   {
  197.     sprintf(sz, "%c%c%c %s", chDay3(DayOfWeek(Mon, Day, Yea)),  SzDate(Mon, Day, Yea, fTrue));
  198.     DrawPrint(sz, gi.kiLite, fFalse);
  199.     DrawPrint(SzTim(Tim), gi.kiLite, fTrue);
  200.     sprintf(sz, " (%cT %s GMT)", Dst != 0.0 ? 'D' : 'S', SzZone(Zon));
  201.   }
  202.  
  203.   DrawPrint(sz, gi.kiLite, fFalse);
  204.  
  205.   if (*ciMain.loc)
  206.     DrawPrint(ciMain.loc, gi.kiLite, fFalse);
  207.  
  208.   DrawPrint(SzLocation(Lon, Lat), gi.kiLite, fFalse);
  209.   sprintf(sz, "%s houses.", szSystem[us.nHouseSystem]);
  210.   DrawPrint(sz, gi.kiLite, fFalse);
  211.  
  212.   sprintf(sz, "%s, %s.", us.fSiderial ? "Sidereal" : "Tropical",
  213.                          us.objCenter == 0 ? "Heliocentric" :
  214.                         (us.objCenter == 1 ? "Geocentric" : szObjName[us.objCenter]));
  215.  
  216.   DrawPrint(sz, gi.kiLite, fFalse);
  217.   sprintf(sz, "Julian Day = %11.4f", JulianDayFromTime(T));
  218.   DrawPrint(sz, gi.kiLite, fFalse);
  219.  
  220.   /* Print house cusp positions. */
  221.  
  222.   DrawPrint("", gi.kiLite, fFalse);
  223.  
  224.   for (i = 1; i <= cSign; i++)
  225.   {
  226.     sprintf(sz, "%2d%s house: ", i, szSuffix[i]);
  227.     y = DrawPrint(sz, kSignB(i), fTrue);
  228.  
  229.     if (!is.fSeconds && (gs.nScale == 100 || !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1)
  230.     {
  231.       s = gi.nScale;
  232.       gi.nScale = gi.nScaleT;
  233.       DrawSign(SFromZ(house[i]), gs.xWin-12*gi.nScaleT,
  234.         y-(yFont/2-1)*gi.nScaleT);
  235.       gi.nScale = s;
  236.     }
  237.  
  238.     DrawPrint(SzZodiac(house[i]), kSignB(SFromZ(house[i])), fFalse);
  239.   }
  240.  
  241.   /* Print planet positions. */
  242.  
  243.   DrawPrint("", gi.kiLite, fFalse);
  244.  
  245.   for (i = 1; i <= oNorm; i++) if (!ignore[i] && !FCusp(i))
  246.   {
  247.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[i]);
  248.     DrawPrint(sz, kObjB[i], fTrue);
  249.     y = DrawPrint(SzZodiac(planet[i]), kSignB(SFromZ(planet[i])), fTrue);
  250.  
  251.     if (!is.fSeconds && i < starLo && (gs.nScale == 100 || !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1)
  252.     {
  253.       s = gi.nScale;
  254.       gi.nScale = gi.nScaleT;
  255.       DrawObject(i, gs.xWin-12*gi.nScaleT, y-(yFont/2-1)*gi.nScaleT);
  256.       gi.nScale = s;
  257.     }
  258.  
  259.     sprintf(sz, "%c ", ret[i] < 0.0 ? chRet : ' ');
  260.     s = FThing(i);
  261.     DrawPrint(sz, gi.kiOn, s);
  262.  
  263.     if (s)
  264.     {
  265.       is.fSeconds = fFalse;
  266.       DrawPrint(SzAltitude(planetalt[i]), gi.kiLite, fFalse);
  267.       is.fSeconds = us.fSeconds;
  268.     }
  269.   }
  270.  
  271.   /* Print star positions. */
  272.  
  273.   for (i = starLo; i <= starHi; i++) if (!ignore[i])
  274.   {
  275.     s = oNorm+starname[i-oNorm];
  276.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[s]);
  277.     DrawPrint(sz, kObjB[s], fTrue);
  278.     DrawPrint(SzZodiac(planet[s]), kSignB(SFromZ(planet[s])), fTrue);
  279.     DrawPrint("  ", gi.kiOn, fTrue);
  280.     DrawPrint(SzAltitude(planetalt[s]), gi.kiLite, fFalse);
  281.   }
  282.  
  283.   /* Print element table information. */
  284.  
  285.   DrawPrint("", gi.kiLite, fFalse);
  286.   CreateElemTable(&et);
  287.  
  288.   sprintf(sz, "Fire: %d, Earth: %d,", et.coElem[eFir], et.coElem[eEar]);
  289.   DrawPrint(sz, gi.kiLite, fFalse);
  290.  
  291.   sprintf(sz, "Air : %d, Water: %d", et.coElem[eAir], et.coElem[eWat]);
  292.   DrawPrint(sz, gi.kiLite, fFalse);
  293.  
  294.   sprintf(sz, "Car: %d, Fix: %d, Mut: %d", et.coMode[0], et.coMode[1], et.coMode[2]);
  295.   DrawPrint(sz, gi.kiLite, fFalse);
  296.  
  297.   sprintf(sz, "Yang: %d, Yin: %d", et.coYang, et.coYin);
  298.   DrawPrint(sz, gi.kiLite, fFalse);
  299.  
  300.   sprintf(sz, "M: %d, N: %d, A: %d, D: %d", et.coMC, et.coIC, et.coAsc, et.coDes);
  301.   DrawPrint(sz, gi.kiLite, fFalse);
  302.  
  303.   sprintf(sz, "Ang: %d, Suc: %d, Cad: %d", et.coModeH[0], et.coModeH[1], et.coModeH[2]);
  304.   DrawPrint(sz, gi.kiLite, fFalse);
  305.  
  306.   sprintf(sz, "Learn: %d, Share: %d", et.coLearn, et.coShare);
  307.   DrawPrint(sz, gi.kiLite, fFalse);
  308.  
  309.   us.fAnsi = a;
  310. }
  311.  
  312.  
  313. /*
  314. ******************************************************************************
  315. ** Map Chart Routines.
  316. ******************************************************************************
  317. */
  318.  
  319. /* Another stream reader, this one is used by the globe drawing routine: */
  320. /* for the next body of land/water, return its name (and color), its     */
  321. /* longitude and latitude, and a vector description of its outline.      */
  322.  
  323. bool FReadWorldData(nam, loc, lin)
  324. char FAR **nam, FAR **loc, FAR **lin;
  325. {
  326.   static char FAR **psz = (char FAR **)szWorldData;
  327.   int i;
  328.  
  329.   *loc = *psz++;
  330.   *lin = *psz++;
  331.   *nam = *psz++;
  332.  
  333.   if (*loc[0])
  334.   {
  335.     if (gs.fPrintMap && gi.fFile)
  336.     {
  337.       i = **nam - '0';
  338.       AnsiColor(i ? kRainbowA[i] : kMainA[7]);
  339.       PrintSz(*nam+1); PrintL();
  340.     }
  341.     return fTrue;
  342.   }
  343.   psz = (char FAR **)szWorldData;  /* Reset stream when no data left. */
  344.   return fFalse;
  345. }
  346.  
  347.  
  348. /* Given longitude and latitude values on a globe, return the window        */
  349. /* coordinates corresponding to them. In other words, project the globe     */
  350. /* onto the view plane, and return where our coordinates got projected to,  */
  351. /* as well as whether our location is hidden on the back side of the globe. */
  352.  
  353. bool FGlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg)
  354. real x1, y1;
  355. int *u, *v, cx, cy, rx, ry, deg;
  356. {
  357.   real j, siny1;
  358.  
  359.   /* Compute coordinates for a general globe invoked with -XG switch. */
  360.  
  361.   if (gi.nMode == gGlobe)
  362.   {
  363.     x1 = Mod(x1+(real)deg);    /* Shift by current globe rotation value. */
  364.  
  365.     if (gs.rTilt != 0.0)
  366.     {
  367.       /* Do another coordinate shift if the globe's equator is tilted any. */
  368.  
  369.       x1 = RFromD(x1); y1 = RFromD(rDegQuad-y1);
  370.       CoorXform(&x1, &y1, RFromD(gs.rTilt));
  371.       x1 = Mod(DFromR(x1)); y1 = rDegQuad-DFromR(y1);
  372.     }
  373.     *v = cy + (int)((real)ry*-RCosD(y1)-rRound);
  374.     *u = cx + (int)((real)rx*-RCosD(x1)*RSinD(y1)-rRound);
  375.     return x1 > rDegHalf;
  376.   }
  377.  
  378.   /* Compute coordinates for a polar globe invoked with -XP switch. */
  379.  
  380.   siny1 = RSinD(y1);
  381.   j = gs.fAlt ? rDegQuad+x1+deg : 270.0-x1-deg;
  382.   *v = cy + (int)(siny1*(real)ry*RSinD(j)-rRound);
  383.   *u = cx + (int)(siny1*(real)rx*RCosD(j)-rRound);
  384.   return gs.fAlt ? y1 < rDegQuad : y1 > rDegQuad;
  385. }
  386.  
  387.  
  388. /* Draw one "Ley line" on the world map, based coordinates given in terms of */
  389. /* longitude and vertical fractional distance from the center of the earth.  */
  390.  
  391. void DrawLeyLine(l1, f1, l2, f2)
  392. real l1, f1, l2, f2;
  393. {
  394.   l1 = Mod(l1); l2 = Mod(l2);
  395.  
  396.   /* Convert vertical fractional distance to a corresponding coordinate. */
  397.  
  398.   f1 = rDegQuad-RAsin(f1)/rPiHalf*rDegQuad;
  399.   f2 = rDegQuad-RAsin(f2)/rPiHalf*rDegQuad;
  400.  
  401.   DrawWrap((int)(l1*(real)gi.nScale+rRound)+1,
  402.            (int)(f1*(real)gi.nScale+rRound)+1,
  403.            (int)(l2*(real)gi.nScale+rRound)+1,
  404.            (int)(f2*(real)gi.nScale+rRound)+1, 1, gs.xWin-2);
  405. }
  406.  
  407.  
  408. /* Draw the main set of planetary Ley lines on the map of the world. This */
  409. /* consists of drawing an icosahedron and then a dodecahedron lattice.    */
  410.  
  411. void DrawLeyLines(deg)
  412. int deg;
  413. {
  414.   real off = (real)deg, phi, h, h1, h2, r, i;
  415.  
  416.   phi = (RSqr(5.0)+1.0)/2.0;                   /* Icosahedron constants. */
  417.   h = 1.0/(phi*2.0-1.0);
  418.   DrawColor(kMainB[6]);
  419.  
  420.   for (i = off; i < rDegMax+off; i += 72.0)    /* Draw icosahedron edges. */
  421.   {
  422.     DrawLeyLine(i,       h, i+72.0,  h);
  423.     DrawLeyLine(i-36.0, -h, i+36.0, -h);
  424.     DrawLeyLine(i,       h, i,       1.0);
  425.     DrawLeyLine(i+36.0, -h, i+36.0, -1.0);
  426.     DrawLeyLine(i,       h, i+36.0, -h);
  427.     DrawLeyLine(i,       h, i-36.0, -h);
  428.   }
  429.  
  430.   r = 1.0/RSqr(3.0)/phi/RCos(RFromD(54.0));    /* Dodecahedron constants. */
  431.   h2 = RSqr(1.0-r*r); h1 = h2/(phi*2.0+1.0);
  432.   DrawColor(kMainB[4]);
  433.  
  434.   for (i = off; i < rDegMax+off; i += 72.0)    /* Draw docecahedron edges. */
  435.   {
  436.     DrawLeyLine(i-36.0,  h2, i+36.0,  h2);
  437.     DrawLeyLine(i,      -h2, i+72.0, -h2);
  438.     DrawLeyLine(i+36.0,  h2, i+36.0,  h1);
  439.     DrawLeyLine(i,      -h2, i,      -h1);
  440.     DrawLeyLine(i+36.0,  h1, i+72.0, -h1);
  441.     DrawLeyLine(i+36.0,  h1, i,      -h1);
  442.   }
  443. }
  444.  
  445.  
  446. /* This major routine draws all of Astrolog's map charts. This means       */
  447. /* either the world map or the constellations, in either rectangular or    */
  448. /* globe hemisphere form. The rectangular chart may also be done in a      */
  449. /* Mollewide projection, for six total combinations. We shift the chart by */
  450. /* specified rotational and tilt values, and may draw on the chart each    */
  451. /* planet at its zenith position on Earth or location in constellations.   */
  452.  
  453. void DrawMap(fSky, fGlobe, deg)
  454. bool fSky, fGlobe;
  455. int deg;
  456. {
  457.   char *nam, *loc, *lin, chCmd;
  458.   int X[objMax], Y[objMax], M[objMax], N[objMax],
  459.     cx = gs.xWin/2,
  460.     cy = gs.yWin/2,
  461.     rx, ry, lon, lat, unit = 12*gi.nScale,
  462.     x, y,
  463.     xold, yold,
  464.     m, n, u, v, i, j, k, l,
  465.     nScl = gi.nScale;
  466.  
  467.   bool fNext = fTrue, fCan;
  468.   real planet1[objMax], planet2[objMax], x1, y1, rT;
  469.  
  470. #ifdef CONSTEL
  471.   char *pch;
  472.   bool fBlank;
  473.   int isz = 0, nC, xT, yT, xDelta, yDelta, xLo, xHi, yLo, yHi;
  474. #endif
  475.  
  476.   /* Set up some variables. */
  477.  
  478.   rx = cx-1; ry = cy-1;
  479.  
  480.   if (fGlobe)
  481.     fCan = (gs.rTilt == 0.0 && gi.nMode != gPolar);
  482.  
  483. #ifdef CONSTEL
  484.  
  485.   /* Draw a dot grid for large rectangular constellation charts. */
  486.  
  487.   if (fSky && !fGlobe && !gs.fMollewide && gi.nScale/gi.nScaleT > 2)
  488.   {
  489.     for (yT = 5; yT < nDegHalf; yT += 5)
  490.     {
  491.       for (xT = 5; xT <= nDegMax; xT += 5)
  492.       {
  493.         DrawColor(xT % 15 == 0 && yT % 10 == 0 ? gi.kiOn : gi.kiGray);
  494.  
  495.         x = xT+deg;
  496.  
  497.         if (x > nDegMax)
  498.           x -= nDegMax;
  499.  
  500.         DrawPoint(x*nScl, yT*nScl);
  501.       }
  502.     }
  503.   }
  504. #endif
  505.  
  506.   loop
  507.   {
  508.     /* Get the next chunk of data to process. Get the starting position, */
  509.     /* map it to the screen, and set the drawing color appropriately.    */
  510.  
  511.     if (fNext)
  512.     {
  513.       fNext = fFalse;
  514.  
  515.       /* For constellations, get data for the next constellation shape. */
  516.  
  517.       if (fSky)
  518.       {
  519.  
  520. #ifdef CONSTEL
  521.         isz++;
  522.         if (isz > cCnstl)
  523.           break;
  524.  
  525.         DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap || !gs.fMollewide) ? kMainB[7] : kRainbowB[6]);
  526.  
  527.         pch = (char *)szDrawConstel[isz];
  528.         lon = nDegMax - (((pch[2]-'0')*10+(pch[3]-'0'))*15+(pch[4]-'0')*10+(pch[5]-'0'));
  529.         lat = 90-((pch[6] == '-' ? -1 : 1)*((pch[7]-'0')*10+(pch[8]-'0')));
  530.         pch += 9;
  531.  
  532.         xLo = xHi = xT = xold = x = lon;
  533.         yLo = yHi = yT = yold = y = lat;
  534.         nC = 0;
  535.  
  536.         if (fGlobe)
  537.         {
  538.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  539.           k = l = fTrue;
  540.         }
  541.         else 
  542.         {
  543.           xold += deg;
  544.           x += deg;
  545.         }
  546. #else
  547.         ;
  548. #endif
  549.       }
  550.  
  551.       /* For world maps, get data for the next coastline piece. */
  552.  
  553.       else /* !fSky */
  554.       {
  555.         if (!FReadWorldData(&nam, &loc, &lin))
  556.           break;
  557.  
  558.         i = nam[0]-'0';
  559.  
  560.         DrawColor((!fGlobe && gi.nMode == gAstroGraph) ? gi.kiOn :
  561.           (gi.nMode == gGlobe && gs.fAlt) ? gi.kiGray :
  562.           (i ? kRainbowB[i] : kMainB[7]));
  563.  
  564.         lon = (loc[0] == '+' ? 1 : -1)*((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
  565.         lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
  566.  
  567.         if (fGlobe)
  568.         {
  569.           x = 180-lon;
  570.           y = 90-lat;
  571.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  572.           k = l = fTrue;
  573.         }
  574.         else
  575.         {
  576.           xold = x = 181-lon+deg;
  577.           yold = y = 91-lat;
  578.         }
  579.       }
  580.     }
  581.  
  582.     /* Get the next unit from the string to draw on the screen as a line. */
  583.  
  584.     if (fSky)
  585.     {
  586.       /* For constellations we have a cache of how long we should keep    */
  587.       /* going in the previous direction, as say "u5" for up five should  */
  588.       /* move our pointer up five times without advancing string pointer. */
  589.  
  590. #ifdef CONSTEL
  591.       if (nC <= 0)
  592.       {
  593.         if (!(chCmd = *pch))
  594.         {
  595.           fNext = fTrue;
  596.           if (gs.fText)
  597.           {
  598.             /* If we've reached the end of current constellation, compute */
  599.             /* the center location in it based on lower and upper bounds  */
  600.             /* we've maintained, and print the name of the constel there. */
  601.  
  602.             xT = xLo + (xHi - xLo)*(szDrawConstel[isz][0]-'1')/8;
  603.             yT = yLo + (yHi - yLo)*(szDrawConstel[isz][1]-'1')/8;
  604.  
  605.             if (xT < 0)
  606.               xT += nDegMax;
  607.             else if (xT > nDegMax)
  608.               xT -= nDegMax;
  609.  
  610.             if (fGlobe)
  611.             {
  612.               if (FGlobeCalc((real)xT, (real)yT, &x, &y, cx, cy, rx, ry, deg))
  613.                 continue;
  614.             }
  615.             else
  616.             {
  617.               xT += deg;
  618.               if (xT > nDegMax)
  619.                 xT -= nDegMax;
  620.  
  621.               if (gs.fMollewide)
  622.                 x = 180*nScl + NMultDiv(xT-180, NMollewide(yT-91), 180L);
  623.               else
  624.                 x = xT*nScl;
  625.  
  626.               y = yT*nScl;
  627.             }
  628.             DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap || !gs.fMollewide) ? gi.kiGray : kMainB[5]);
  629.             DrawSz(szCnstlAbbrev[isz], x, y, dtCent);
  630.           }
  631.           continue;
  632.         }
  633.         pch++;
  634.  
  635.         /* Get the next direction and distance from constellation string. */
  636.  
  637.         if (fBlank = (chCmd == 'b'))
  638.           chCmd = *pch++;
  639.  
  640.         xDelta = yDelta = 0;
  641.  
  642.         switch (chCmd) {
  643.         case 'u': yDelta = -1;                      break;    /* Up    */
  644.         case 'd': yDelta =  1;                      break;    /* Down  */
  645.         case 'l': xDelta = -1;                      break;    /* Left  */
  646.         case 'r': xDelta =  1;                      break;    /* Right */
  647.         case 'U': yDelta = -1; nC = (yT-1)%10+1;    break;    /* Up until    */
  648.         case 'D': yDelta =  1; nC = 10-yT%10;       break;    /* Down until  */
  649.         case 'L': xDelta = -1; nC = (xT+599)%15+1;  break;    /* Left until  */
  650.         case 'R': xDelta =  1; nC = 15-(xT+600)%15; break;    /* Right until */
  651.         default: PrintError("Bad draw.");                     /* Shouldn't happen. */
  652.         }
  653.         if (chCmd >= 'a')
  654.           nC = NFromPch(&pch);    /* Figure out how far to draw. */
  655.       }
  656.       nC--;
  657.  
  658.       xT += xDelta; x += xDelta;
  659.       yT += yDelta; y += yDelta;
  660.  
  661.       if (fBlank)
  662.       {
  663.         xold = x; yold = y;    /* We occasionally want to move the pointer */
  664.         l = fFalse;            /* without drawing the line on the screen.  */
  665.         continue;
  666.       }
  667.  
  668.       if (xT < xLo)         /* Maintain our bounding rectangle for this */
  669.         xLo = xT;           /* constellation if we crossed over it any. */
  670.       else if (xT > xHi)
  671.         xHi = xT;
  672.  
  673.       if (yT < yLo)
  674.         yLo = yT;
  675.       else if (yT > yHi)
  676.         yHi = yT;
  677. #else
  678.       ;
  679. #endif
  680.     }
  681.  
  682.     else /* !fSky */
  683.     {
  684.       /* Get the next unit from the much simpler world map strings. */
  685.  
  686.       if (!(chCmd = *lin))
  687.       {
  688.         fNext = fTrue;
  689.         continue;
  690.       }
  691.       lin++;
  692.  
  693.       /* Each unit is exactly one character in the coastline string. */
  694.  
  695.       if (chCmd == 'L' || chCmd == 'H' || chCmd == 'G')
  696.         x--;
  697.       else if (chCmd == 'R' || chCmd == 'E' || chCmd == 'F')
  698.         x++;
  699.  
  700.       if (chCmd == 'U' || chCmd == 'H' || chCmd == 'E')
  701.         y--;
  702.       else if (chCmd == 'D' || chCmd == 'G' || chCmd == 'F')
  703.         y++;
  704.     }
  705.  
  706.     /* Transform map coordinates to screen coordinates and draw a line. */
  707.  
  708.     while (x >= nDegMax)    /* Take care of coordinate wrap around. */
  709.       x -= nDegMax;
  710.  
  711.     while (x < 0)
  712.       x += nDegMax;
  713.  
  714.     if (abs(x-xold) > nDegHalf)
  715.       xold = x;
  716.  
  717.     if (fGlobe)
  718.     {
  719.       /* For globes, we have to go do a complicated transformation, and not */
  720.       /* draw when we're hidden on the back side of the sphere. We're smart */
  721.       /* and try to only do the slow stuff when we know we'll be visible.   */
  722.  
  723.       if (fCan)
  724.       {
  725.         k = x+deg;
  726.         if (k >= nDegMax)
  727.           k -= nDegMax;
  728.         k = (k <= 180);
  729.       }
  730.  
  731.       if (k && !FGlobeCalc((real)x, (real)y, &u, &v, cx, cy, rx, ry, deg))
  732.       {
  733.         if (l)
  734.           DrawLine(m, n, u, v);
  735.  
  736.         m = u; n = v;
  737.         l = fTrue;
  738.       }
  739.       else
  740.         l = fFalse;
  741.     }
  742.  
  743.     else /* !fGlobe */
  744.     {
  745.       /* Rectangular maps are much simpler, with screen coordinates      */
  746.       /* proportional to internal coords. For the Mollewide projection   */
  747.       /* we have to apply a factor to the horizontal positioning though. */
  748.  
  749.       if (gs.fMollewide && gi.nMode != gAstroGraph)
  750.       {
  751.         DrawLine(180*nScl + NMultDiv(xold-180, NMollewide(yold-91), 180L), yold*nScl,
  752.                  180*nScl + NMultDiv(x-180,    NMollewide(y-91),    180L), y*nScl);
  753.       }
  754.       else DrawLine(xold*nScl, yold*nScl, x*nScl, y*nScl);
  755.       xold = x; yold = y;
  756.     }
  757.   }
  758.  
  759.   /* Draw the outline of the map, either a circle around globes or a */
  760.   /* Mollewide type ellipse for that type of rectangular chart.      */
  761.  
  762.   DrawColor(gi.kiOn);
  763.  
  764.   if (!fGlobe)
  765.   {
  766.     if (gs.fMollewide && gi.nMode != gAstroGraph)
  767.     {
  768.       if (!gs.fAlt)
  769.       {
  770.         for (xold = 0, y = -89; y <= 90; y++, xold = x)
  771.         {
  772.           for (x = NMollewide(y), i = -1; i <= 1; i += 2)
  773.           {
  774.             DrawLine(180*nScl + i*xold - (i == 1), (90+y)*nScl, 180*nScl + i*x - (i == 1), (91+y)*nScl);
  775.           }
  776.         }
  777.       }
  778.     }
  779.   }
  780.   else DrawEllipse(0, 0, gs.xWin-1, gs.yWin-1);
  781.  
  782.   /* Now, if we are in an appropriate bonus chart mode, draw each planet at */
  783.   /* its zenith or visible location on the globe or map, if not hidden.     */
  784.  
  785.   if (!gs.fAlt || (gi.nMode != gGlobe && (!fSky || gi.nMode != gWorldMap || gs.fMollewide)))
  786.     return;
  787.  
  788.   rT = gs.fConstel ? rDegHalf - (fGlobe ? 0.0 : (real)deg) : Lon;
  789.  
  790.   if (rT < 0.0)
  791.     rT += rDegMax;
  792.  
  793.   for (i = 1; i <= cObj; i++)
  794.   {
  795.     planet1[i] = RFromD(Tropical(planet[i]));
  796.     planet2[i] = RFromD(planetalt[i]);
  797.  
  798.     EclToEqu(&planet1[i], &planet2[i]);    /* Calculate zenith long. & lat. */
  799.   }
  800.  
  801.   /* Compute screen coordinates of each object, if it's even visible. */
  802.  
  803.   for (i = 1; i <= cObj; i++) if (FProper(i))
  804.   {
  805.     if (fSky)
  806.       x1 = planet1[i];
  807.     else
  808.       x1 = planet1[oMC]-planet1[i];
  809.  
  810.     if (x1 < 0.0)   x1 += 2.0*rPi;
  811.     if (x1 > rPi)   x1 -= 2.0*rPi;
  812.  
  813.     x1 = Mod(rDegHalf-rT-DFromR(x1));
  814.     y1 = rDegQuad-DFromR(planet2[i]);
  815.  
  816.     if (fGlobe)
  817.     {
  818.       X[i] = FGlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u;
  819.       Y[i] = v;
  820.     }
  821.     else
  822.     {
  823.       X[i] = (int)(x1 * (real)nScl);
  824.       Y[i] = (int)(y1 * (real)nScl);
  825.     }
  826.     M[i] = X[i]; N[i] = Y[i]+unit/2;
  827.   }
  828.  
  829.   /* Now that we have the coordinates of each object, figure out where to   */
  830.   /* draw the glyphs. Again we try not to draw glyphs on top of each other. */
  831.  
  832.   for (i = 1; i <= cObj; i++) if (FProper(i))
  833.   {
  834.     k = l = gs.xWin+gs.yWin;
  835.  
  836.     /* For each planet, we draw the glyph either right over or right under */
  837.     /* the actual zenith location point. So, find out the closest distance */
  838.     /* of any other planet assuming we place ours at both possibilities.   */
  839.  
  840.     for (j = 1; j < i; j++) if (FProper(j))
  841.     {
  842.       k = Min(k, abs(M[i]-M[j])+abs(N[i]-N[j]));
  843.       l = Min(l, abs(M[i]-M[j])+abs(N[i]-unit-N[j]));
  844.     }
  845.  
  846.     /* Normally, we put the glyph right below the actual point. If however  */
  847.     /* another planet is close enough to have their glyphs overlap, and the */
  848.     /* above location is better, then we'll draw the glyph above instead.   */
  849.  
  850.     if (k < unit || l < unit)
  851.     {
  852.       if (k < l)
  853.         N[i] -= unit;
  854.     }
  855.   }
  856.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i))      /* Draw the */
  857.     DrawObject(i, M[i], N[i]);                                  /* glyphs.  */
  858.  
  859.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i))
  860.   {
  861.     DrawColor(kObjB[i]);
  862.     DrawSpot(X[i], Y[i]);
  863.   }
  864. }
  865.  
  866.  
  867. /* Create a chart in the window based on the current graphics chart mode. */
  868. /* This is the main dispatch routine for all of the program's graphics.   */
  869.  
  870. void DrawChartX()
  871. {
  872.   char sz[cchSzDef];
  873.   int i;
  874.   bool fT;
  875.  
  876.   gi.nScale = gs.nScale/100;
  877.  
  878.   if (gs.fBitmap || gs.fMeta)
  879.     PrintNotice("Creating graphics chart in memory.");
  880.   DrawClearScreen();
  881.  
  882. #ifdef CONSTEL
  883.   fT = gs.fConstel;
  884. #else
  885.   fT = fFalse;
  886. #endif
  887.  
  888.   switch (gi.nMode) {
  889.  
  890.   case gWheel:
  891.   case gHouse:
  892.     if (us.nRel > rcDual)
  893.       XChartWheel();
  894.     else
  895.       XChartWheelRelation();
  896.     break;
  897.  
  898.   case gGrid:
  899.     if (us.nRel > rcDual)
  900.       XChartGrid();
  901.     else
  902.       XChartGridRelation();
  903.     break;
  904.  
  905.   case gHorizon:
  906.     if (us.fPrimeVert)
  907.       XChartHorizonSky();
  908.     else
  909.       XChartHorizon();
  910.     break;
  911.  
  912.   case gOrbit:
  913.     XChartOrbit();
  914.     break;
  915.  
  916.   case gDisposit:
  917.     XChartDispositor();
  918.     break;
  919.  
  920.   case gAstroGraph:
  921.     DrawMap(fFalse, fFalse, gs.nRot);  /* First draw map of world.           */
  922.     XChartAstroGraph();                /* Then draw astro-graph lines on it. */
  923.     break;
  924.  
  925.   case gCalendar:
  926.     XChartCalendar();
  927.     break;
  928.  
  929.   case gEphemeris:
  930.     XChartEphemeris();
  931.     break;
  932.  
  933.   case gWorldMap:
  934.     DrawMap(fT, fFalse, gs.nRot);           /* First draw map of world. */
  935.     if (!fT && gs.fAlt && !gs.fMollewide)   /* Then maybe Ley lines.    */
  936.       DrawLeyLines(gs.nRot);
  937.     break;
  938.  
  939.   case gGlobe:
  940.   case gPolar:
  941.     DrawMap(fT, fTrue, gs.nRot);
  942.     break;
  943.  
  944. #ifdef BIORHYTHM
  945.   case gBiorhythm:
  946.     XChartBiorhythm();
  947.     break;
  948. #endif
  949.   }
  950.  
  951.   /* Print text showing chart information at bottom of window. */
  952.  
  953.   DrawColor(gi.kiLite);
  954.   if (fDrawText)
  955.   {
  956.     if (Mon == -1)
  957.       sprintf(sz, "(No time or space)");
  958.  
  959.     else if (us.nRel == rcComposite)
  960.       sprintf(sz, "(Composite)");
  961.  
  962.     else
  963.     {
  964.       fT = us.fAnsi; us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS));
  965.       i = DayOfWeek(Mon, Day, Yea);
  966.  
  967.       sprintf(sz, "%c%c%c %s %s (%cT %s GMT) %s", chDay3(i),
  968.         SzDate(Mon, Day, Yea, 2), SzTim(Tim), Dst != 0.0 ? 'D' : 'S',
  969.         SzZone(Zon), SzLocation(Lon, Lat));
  970.       us.fAnsi = fT;
  971.     }
  972.     DrawSz(sz, gs.xWin/2, gs.yWin-3*gi.nScaleT, dtBottom | dtErase);
  973.   }
  974.  
  975.   /* Draw a border around the chart if the mode is set and appropriate. */
  976.  
  977.   if (fDrawBorder)
  978.     DrawEdgeAll();
  979. }
  980. #endif /* GRAPH */
  981.  
  982. /* xcharts0.c */
  983.